package com.cxyd.modules.wms.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cxyd.common.Utils.BeanUtils;
import com.cxyd.common.exception.RootException;
import com.cxyd.common.page.PageData;
import com.cxyd.common.service.impl.CrudServiceImpl;
import com.cxyd.common.utils.ConvertUtils;
import com.cxyd.common.utils.ProcResult;
import com.cxyd.modules.core.service.SerialNumberService;
import com.cxyd.modules.wms.dao.*;
import com.cxyd.modules.wms.dto.PurchaseDTO;
import com.cxyd.modules.wms.dto.SupplierDTO;
import com.cxyd.modules.wms.entity.PurchaseBakEntity;
import com.cxyd.modules.wms.entity.PurchaseDetailBakEntity;
import com.cxyd.modules.wms.entity.PurchaseDetailEntity;
import com.cxyd.modules.wms.entity.PurchaseEntity;
import com.cxyd.modules.wms.excel.easy.PurchaseCPEasyExcel;
import com.cxyd.modules.wms.excel.easy.PurchaseEasyExcel;
import com.cxyd.modules.wms.excel.listener.PurchaseCPExcelListener;
import com.cxyd.modules.wms.excel.listener.PurchaseExcelListener;
import com.cxyd.modules.wms.service.PurchaseDetailService;
import com.cxyd.modules.wms.service.PurchaseService;
import com.cxyd.modules.wms.service.SpuService;
import com.cxyd.modules.wms.service.SupplierService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 入库主单
 *
 * @author g_Cycle gengruyi01@163.com
 * @since 1.0.0 2023-04-27
 */
@Slf4j
@Service
public class PurchaseServiceImpl extends CrudServiceImpl<PurchaseDao, PurchaseEntity, PurchaseDTO> implements PurchaseService {
    @Resource
    private SerialNumberService serialNumberService;
    @Resource
    private PurchaseDetailDao purchaseDetailDao;
    @Resource
    private SupplierService supplierService;
    @Resource
    private PurchaseDao purchaseDao;
    @Resource
    private PurchaseBakDao purchaseBakDao;
    @Resource
    private PurchaseDetailBakDao purchaseDetailBakDao;
    @Resource
    @Lazy
    private PurchaseDetailService purchaseDetailService;
    @Resource
    @Lazy
    private PurchaseService purchaseService;
    @Resource
    private SpuService spuService;
    @Resource
    private SupplierDao supplierDao;

    @Override
    public PageData<PurchaseDTO> page(Map<String, Object> params) {
        //1.查询主单信息
        IPage<PurchaseEntity> page = baseDao.selectViewPage(
                getPage(params, "", false),
                getWrapper(params)
        );
        return getPageData(page, PurchaseDTO.class);
    }

    @Override
    public QueryWrapper<PurchaseEntity> getWrapper(Map<String, Object> params) {
        String id = (String) params.get("id");
        String purchaseNo = (String) params.get("purchaseNo");
        String deliverNo = (String) params.get("deliverNo");
        String purchaseSt = (String) params.get("purchaseSt");
        String purchaseType = (String) params.get("purchaseType");

        QueryWrapper<PurchaseEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(id), "id", id);
        wrapper.eq(StringUtils.isNotBlank(purchaseNo), "PURCHASE_NO", purchaseNo);
        wrapper.eq(StringUtils.isNotBlank(purchaseSt), "PURCHASE_ST", purchaseSt);
        wrapper.eq(StringUtils.isNotBlank(purchaseType), "purchase_type", purchaseType);
        wrapper.like(StringUtils.isNotBlank(deliverNo), "deliver_no", deliverNo);
        //新增排序
        wrapper.orderBy(true, true, "(CASE purchase_st " +
                "WHEN 1 THEN 0 " +
                "WHEN 0 THEN 1 " +
                "WHEN 2 THEN 2 " +
                "WHEN 9 THEN 3 " +
                "ELSE 4 END)");
        wrapper.orderBy(true, true, "create_date");
        return wrapper;
    }

    @Override
    public void save(PurchaseDTO dto) {
        if (ObjectUtils.isNotEmpty(this.findByDriverNo(dto.getDeliverNo()))) {
            throw new RootException("当前收货单已存在！");
        }
        //1.获取订单编号
        String purchaseNo = serialNumberService.getSerialNumberByCode("purchase");
        //2.将dto转换为单据实体类
        PurchaseEntity entity = ConvertUtils.sourceToTarget(dto, PurchaseEntity.class);
        //3.单据编号填充至实体类
        entity.setPurchaseNo(purchaseNo);
        entity.setPurchaseType("物料入库");
//        获取供应商信息
        SupplierDTO supplier = supplierService.getSupplierByCode(dto.getSupplierCode());
        if (supplier != null) {
            entity.setSupplierName(supplier.getSupplierName());
        }
        //4.将数据写入数据库
        insert(entity);
    }

    @Override
    public PurchaseDTO selectByParams(Map<String, Object> params) {
        String purchaseNo = (String) params.get("purchaseNo");
        String deliverNo = (String) params.get("deliverNo");
        String spuName = (String) params.get("spuName");
        QueryWrapper<PurchaseEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(purchaseNo), "purchase_no", purchaseNo);
        wrapper.eq(StringUtils.isNotBlank(deliverNo), "deliver_no", deliverNo);
        wrapper.like(StringUtils.isNotBlank(spuName), "spu_name", spuName);
        PurchaseEntity entity = baseDao.selectOne(wrapper);
        return ConvertUtils.sourceToTarget(entity, PurchaseDTO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(@RequestBody Long[] ids) {
        for (int i = 0; i < ids.length; i++) {
            deletePurchaseById(ids[i]);
        }
    }

    private void deletePurchaseById(Long id) {
        PurchaseEntity entity = baseDao.selectById(id);
        //判断明细状态是否为初始状态
        if (entity.getPurchaseSt() == 1) {
            throw new RootException("[收货中]状态的主单不可以删除！");
        }
        //删除此单据下的所有明细
        List<PurchaseDetailEntity> list = purchaseDetailService.findByPurchaseId(id);
        for (PurchaseDetailEntity purchaseDetailEntity : list) {
            purchaseDetailService.deleteById(purchaseDetailEntity.getDetailId());
        }
        //删除
        baseDao.deleteById(id);
    }

    @Override
    public ProcResult residualBackRegister(Map<String, Object> params) {
        //对主要参数进行校验(contNo,detailId,actlQty等)
        String contNo = (String) params.get("contNo");
        if (StringUtils.isBlank(contNo)) {
            return new ProcResult().result("123", "托盘条码不能为空!");
        }
        String stnNo = (String) params.get("stationNo");
        if (StringUtils.isBlank(stnNo)) {
            return new ProcResult().result("123", "所选站台不能为空!");
        }
        String spuNo = (String) params.get("spuNo");
        if (StringUtils.isBlank(spuNo)) {
            return new ProcResult().result("123", "物料编号不能为空!");
        }
//        String spuSize = (String) params.get("spuSize");
//        if (StringUtils.isBlank(spuSize)) {
//            return new ProcResult().result("123", "尺寸不能为空!");
//        }
        String actlQty = (String) params.get("actlQty");
        if (StringUtils.isBlank(actlQty)) {
            return new ProcResult().result("123", "件数不能为空!");
        }
        String userId = (String) params.get("userId");
        if (StringUtils.isBlank(userId)) {
            params.put("userId", 1004L);
        }
        String code = "0";
        String msg = "执行成功";
        return new ProcResult().result(code, msg);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uploadFile(MultipartFile file) {
        try {
            EasyExcel.read(file.getInputStream(),
                    PurchaseEasyExcel.class,
                    new PurchaseExcelListener(purchaseService,
                            purchaseDetailService, spuService)).sheet().doRead();
        } catch (IOException e) {
            throw new RootException("文件读取失败！");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uploadCPFile(MultipartFile file) {
        try {
            EasyExcel.read(file.getInputStream(),
                    PurchaseCPEasyExcel.class,
                    new PurchaseCPExcelListener(purchaseService,
                            purchaseDetailService, spuService, supplierDao)).sheet().doRead();
        } catch (IOException e) {
            throw new RootException("文件读取失败！");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void backUp(Date date, Integer num) {
        while (true) {
            List<PurchaseEntity> purchaseEntities = purchaseDao.selectForBackup(date, num);
            if (CollectionUtils.isEmpty(purchaseEntities)) {
                break;
            }
            List<PurchaseBakEntity> list = new ArrayList<>();
            for (PurchaseEntity purchase : purchaseEntities) {
                PurchaseBakEntity purchaseBak = new PurchaseBakEntity();
                BeanUtils.copyProperties(purchase, purchaseBak);
                list.add(purchaseBak);
            }
            purchaseBakDao.batchInsert(list);
            List<Long> ids = purchaseEntities.stream().map(PurchaseEntity::getPurchaseId).collect(Collectors.toList());
            purchaseDao.deleteBatchIds(ids);
        }

        while (true) {
            List<PurchaseDetailEntity> purchaseDetailEntityList = purchaseDetailDao.selectForBackup(date, num);
            if (CollectionUtils.isEmpty(purchaseDetailEntityList)) {
                break;
            }
            List<PurchaseDetailBakEntity> list = new ArrayList<>();
            for (PurchaseDetailEntity purchaseDetail : purchaseDetailEntityList) {
                PurchaseDetailBakEntity purchaseDetailBak = new PurchaseDetailBakEntity();
                BeanUtils.copyProperties(purchaseDetail, purchaseDetailBak);
                list.add(purchaseDetailBak);
            }
            purchaseDetailBakDao.batchInsert(list);
            List<Long> ids = purchaseDetailEntityList.stream().map(PurchaseDetailEntity::getDetailId).collect(Collectors.toList());
            purchaseDetailDao.deleteBatchIds(ids);
        }
    }

    @Override
    public PurchaseEntity findByDriverNo(String driverNo) {
        QueryWrapper<PurchaseEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(PurchaseEntity::getDeliverNo, driverNo);
        return baseDao.selectOne(qw);
    }
}